<?php


namespace Rebuild\HttpServer;

use FastRoute\Dispatcher;
use Hyperf\HttpMessage\Server\Request as Psr7Request;
use Hyperf\HttpMessage\Server\Response as Psr7Response;
use Hyperf\Utils\Context;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Rebuild\HttpServer\Router\DispatherFactory;
use Swoole\http\Request as SwooleRequset;
use Swoole\Http\Response as SwooleResponse;
use function FastRoute\simpleDispatcher;

class Server
{
    /**
     * @var Dispatcher
     */
    protected $dispatcher;

    /**
     * @var CoreMiddleware
     */
    protected $coreMiddleware;

    public function __construct(DispatherFactory $dispatherFactory)
    {
        $this->dispatcher = $dispatherFactory->getDispatcher('http');
        $this->coreMiddleware = new CoreMiddleware($dispatherFactory);
    }

    public function onRequest(SwooleRequset $request, SwooleResponse $response): void
    {
        /**
         * @var  \Psr\Http\Message\RequestInterface $psr7Request
         * @var  ResponseInterface $psr7Response
         */
        [$psr7Request, $psr7Response] = $this->initRequestAndResponse($request, $response);
        $method = $psr7Request->getMethod();
        $uri = $psr7Request->getUri()->getPath();

        $this->coreMiddleware->dispatch($psr7Request);
        $routeInfo = $this->dispatcher->dispatch($method, $uri);
        switch ($routeInfo[0]) {
            case Dispatcher::NOT_FOUND:
                $response->status(404);
                $response->end('Not Found');
                break;
            case Dispatcher::METHOD_NOT_ALLOWED:
                $allowedMethods = $routeInfo[1];
                $response->status(405);
                $response->header('Method_Allowed', implode(',', $allowedMethods));
                break;
            case Dispatcher::FOUND:
                $handler = $routeInfo[1];
                $vars = $routeInfo[2];
                [$controller, $action] = $handler;
                $instance = new $controller();
                $result = $instance->$action(...$vars);
                $response->end($result);
                break;
        }

    }

    public function initRequestAndResponse(SwooleRequset $request, SwooleResponse $response): array
    {
        Context::set(ResponseInterface::class, $psr7Response = new Psr7Response());

        if ($request instanceof ServerRequestInterface) {
            $psr7Request = $request;
        } else {
            $psr7Request = Psr7Request::loadFromSwooleRequest($request);
        }

        Context::set(ServerRequestInterface::class, $psr7Request);
        return [$psr7Request, $psr7Response];
    }

}